﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization;

namespace AppEntity
{
    
    /// <summary>
    /// C# String 基础类库扩展
    /// </summary>   
    public static class StringExtension
    {
        /// <summary>
        /// 在执行 RemoveInvalidCharForXml() 后，再把转义字符串为合法的xml字符。&lt;=&amp;lt;，&gt;=&amp;gt; "=&amp;quot; '=&amp;apos; &amp;=&amp;amp;
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToXmlSafeString(this string str)
        {
            return str.RemoveInvalidCharForXml().Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("'", "&apos;");
        }

        /// <summary>
        /// 判断用来组成 XML 的字符串是否存在特殊字符，如 &amp;#01;~&amp;#08;，&amp;#11~&amp;#12;，&amp;#14~&amp;#32;，这些字符会使 XmlDocument.LoadXml(str) 执行时产生异常。
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsExistsInvalidCharForXml(this string str)
        {
            char[] arr = str.ToCharArray();
            foreach (char cc in arr)
            {
                int ss = (int)cc;
                if (((ss >= 0) && (ss <= 8)) || ((ss >= 11) && (ss <= 12)) || ((ss >= 14) && (ss < 32)))
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 移除用来组成 XML 字符串中的特殊字符，如 &amp;#01;~&amp;#08;，&amp;#11~&amp;#12;，&amp;#14~&amp;#32;，这些字符会使 XmlDocument.LoadXml(str) 执行时产生异常。
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string RemoveInvalidCharForXml(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return "";
            char[] arr = str.ToCharArray();
            StringBuilder sb = new StringBuilder();
            foreach (char cc in arr)
            {
                int ss = (int)cc;
                if (((ss >= 0) && (ss <= 8)) || ((ss >= 11) && (ss <= 12)) || ((ss >= 14) && (ss < 32)))
                {
                    continue;
                }
                sb.Append(cc);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 格式化字符串，内部调用 string.Format(str, args);
        /// </summary>
        /// <param name="str"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static string FormatString(this string str, params object[] args)
        {
            return string.Format(str, args);
        }
        /// <summary>
        /// 用指定的字符串连接字符串数组
        /// </summary>
        /// <param name="StrArr"></param>
        /// <param name="Separator"></param>
        /// <returns></returns>
        public static string Join(this string[] StrArr, string Separator)
        {
            return string.Join(Separator, StrArr);
        }
        /// <summary>
        /// 用指定的字符串连接字符串数组
        /// </summary>
        /// <param name="StrArr"></param>
        /// <param name="Separator"></param>
        /// <param name="StartIndex">数组开始连接处</param>
        /// <param name="Count">需要连接的长度</param>
        /// <returns></returns>
        public static string Join(this string[] StrArr, string Separator, int StartIndex, int Count)
        {
            return string.Join(Separator, StrArr, StartIndex, Count);
        }

        /// <summary>
        /// 使用 XmlSerializer.Deserialize 反序列化当前字符串为指定类型的对象。
        /// 该方法位于 SBS.Common.dll
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="str">当前字符串</param>
        /// <returns></returns>
        public static T Deserialize<T>(this string str)
        {
            XmlSerializer Serializer = new XmlSerializer(typeof(T));
            byte[] buf = Encoding.Default.GetBytes(str);
            MemoryStream stream = new MemoryStream(buf);
            return (T)Serializer.Deserialize(stream);
        }

        /// <summary>
        /// 使用 DataContractSerializer.Deserialize 反序列化当前字符串为指定类型的对象。
        /// 该方法位于 SBS.Common.dll
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="str">当前字符串</param>
        /// <returns></returns>
        public static T DeserializeToData<T>(this string str)
        {
            DataContractSerializer Serializer = new DataContractSerializer(typeof(T));
            byte[] buf = Encoding.Default.GetBytes(str);
            MemoryStream stream = new MemoryStream(buf);
            return (T)Serializer.ReadObject(stream);
        }

        /// <summary>
        /// 使用正则表达式替换字符串。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="RegexPattern"></param>
        /// <param name="TargetString"></param>
        /// <returns></returns>
        public static string ReplaceRegExp(this string str, string RegexPattern, string TargetString)
        {
            return System.Text.RegularExpressions.Regex.Replace(str, RegexPattern, TargetString);
        }

        /// <summary>
        /// 使用正则表达式替换字符串，支持正则的替换选项。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="RegexPattern"></param>
        /// <param name="TargetString"></param>
        /// <param name="Options"></param>
        /// <returns></returns>
        public static string ReplaceRegExp(this string str, string RegexPattern, string TargetString, RegexOptions Options)
        {
            return System.Text.RegularExpressions.Regex.Replace(str, RegexPattern, TargetString, Options);
        }

        /// <summary>
        /// 把Uri中的查询部分转换为字典
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        public static Dictionary<string, string> QueryStringToDictionary(this Uri uri)
        {
            string QueryString = uri.Query;
            if (string.IsNullOrEmpty(QueryString)) return null;
            return AppEntity.Common.Utility.QueryStringToDictionary(QueryString);
        }

        /// <summary>
        /// 把字符串中的双字节字符转换为 unicode 码。如“abc中文”转换为“abc&amp;#20013;&amp;#25991;”
        /// </summary>
        /// <param name="str"></param>
        /// <returns>返回新字符串</returns>
        public static string ToUnicode(this string str)
        {
            char[] arr = str.ToCharArray();
            StringBuilder sb = new StringBuilder(arr.Length);
            foreach (char c in arr)
            {
                int n = (int)c;
                if (n < 0 || n > 255)
                {
                    sb.Append("&#" + n + ";");
                }
                else
                {
                    sb.Append(c);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 转换字符串为为Int32整数值。如果转换失败，将返回传入的默认值 ValueWhenParseFail
        /// </summary>
        /// <param name="str"></param>
        /// <param name="ValueWhenParseFail">转换失败时返回的默认值</param>
        /// <returns></returns>
        public static int ToInt32(this string str, int ValueWhenParseFail)
        {
            int t = ValueWhenParseFail;
            if (Int32.TryParse(str, out t))
            {
                return t;
            }
            return ValueWhenParseFail;
        }

        /// <summary>
        /// 转换字符串为为Int32整数值。如果转换失败，将返回 0
        /// </summary>
        /// <param name="str"></param>        
        /// <returns></returns>
        public static int ToInt32(this string str)
        {
            return str.ToInt32(0);
        }

        /// <summary>
        /// 转换字符串为为Int64整数值。如果转换失败，将返回传入的默认值 ValueWhenParseFail
        /// </summary>
        /// <param name="str"></param>
        /// <param name="ValueWhenParseFail">转换失败时返回的默认值</param>
        /// <returns></returns>
        public static long ToInt64(this string str, long ValueWhenParseFail)
        {
            long t = ValueWhenParseFail;
            if (Int64.TryParse(str, out t))
            {
                return t;
            }
            return ValueWhenParseFail;
        }

        /// <summary>
        /// 转换字符串为为Int64整数值。如果转换失败，将返回 0
        /// </summary>
        /// <param name="str"></param>        
        /// <returns></returns>
        public static long ToInt64(this string str)
        {
            return str.ToInt64(0);
        }

        /// <summary>
        /// 转换字符串为为 double 双精度浮点数。如果转换失败，将返回传入的默认值 ValueWhenParseFail
        /// </summary>
        /// <param name="str"></param>
        /// <param name="ValueWhenParseFail">转换失败时返回的默认值</param>
        /// <returns></returns>
        public static double ToDouble(this string str, double ValueWhenParseFail)
        {
            double t = ValueWhenParseFail;
            if (double.TryParse(str, out t))
            {
                return t;
            }
            return ValueWhenParseFail;
        }

        /// <summary>
        /// 转换字符串为为 double 双精度浮点数。如果转换失败，将返回 0
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static double ToDouble(this string str)
        {
            return str.ToDouble(0);
        }

        /// <summary>
        /// 转换字符串为为 float 单精度浮点数。如果转换失败，将返回传入的默认值 ValueWhenParseFail
        /// </summary>
        /// <param name="str"></param>
        /// <param name="ValueWhenParseFail"></param>
        /// <returns></returns>
        public static float ToFloat(this string str, float ValueWhenParseFail)
        {
            float t = ValueWhenParseFail;
            if (float.TryParse(str, out t))
            {
                return t;
            }
            return ValueWhenParseFail;
        }

        /// <summary>
        /// 转换字符串为为 float 单精度浮点数。如果转换失败，将返回 0
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static float ToFloat(this string str)
        {
            return str.ToFloat(0);
        }

        /// <summary>
        /// 解析字符串为 DateTime 对象。如果解析失败，返回 ValueWhenParseFail。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="ValueWhenParseFail">解析失败时返回的 DateTime 对象</param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string str, DateTime ValueWhenParseFail)
        {
            DateTime dt = ValueWhenParseFail;
            if (DateTime.TryParse(str, out dt))
            {
                return dt;
            }
            return ValueWhenParseFail;
        }

        /// <summary>
        /// 解析字符串为 DateTime 对象。如果解析失败，返回 Now
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string str)
        {
            DateTime dt;
            if (DateTime.TryParse(str, out dt))
            {
                return dt;
            }
            return DateTime.Now;
        }

        //自动转换字符串 true，1, on 为布尔值True，false,0, off, 空字符串为False。其他默认为 False。
        public static bool ToBoolean(this string str)
        {
            str = str.Trim().ToLower();
            if (string.IsNullOrEmpty(str) || str == "off") return false;
            if (str == "1" || str == "on") { return true; }
            bool bl = false;
            if (bool.TryParse(str, out bl))
            {
                return bl;
            }
            return bl;
        }

        /// <summary>
        /// 返回字符串的 MD5 值
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string MD5(this string str)
        {
            return AppEntity.Common.Utility.MD5(str);
        }
        /// <summary>
        /// 返回字符串的 SHA1 值
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string SHA1(this string str)
        {
            return AppEntity.Common.Utility.SHA1(str);
        }

        /// <summary>
        /// 当前字符串是否数字，如果包含0~9，减号，小数点以外的字符都返回 false。内部使用 char.IsNumber() 实现。123-456 为 false, -.123 为 true。
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsNumber(this string str)
        {
            char[] Chars = str.ToCharArray();
            bool HasNumber = false;
            for (int i = 0; i < Chars.Length; i++)
            {
                char c = Chars[i];
                if (c == '-' && i != 0)
                {
                    return false;
                }
                else if (c == '-' && i == 0)
                {
                    continue;
                }

                if (c == '.') continue;
                if (char.IsNumber(c) == false)
                {
                    return false;
                }
                else
                {
                    HasNumber = true;
                }
            }
            return HasNumber;
        }

        /// <summary>
        /// 从左边开始查找子字符串，从开始到指定的字符（不包含此字符）。如果不包含指定的字符，返回null。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Char"></param>
        /// <returns></returns>
        public static string SubstringBefore(this string str, char Char)
        {
            int Pos = str.IndexOf(Char);
            if (Pos < 0) return null;
            return str.Left(Pos);
        }
        public static string SubstringBefore(this string str, string Key)
        {
            int Pos = str.IndexOf(Key);
            if (Pos < 0) return null;
            return str.Left(Pos);
        }
        /// <summary>
        /// 从左边开始查找子字符串，从指定的字符开始（不包含此字符）到结尾。如果不包含指定的字符，返回null。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Char"></param>
        /// <returns></returns>
        public static string SubstringAfter(this string str, char Char)
        {
            int Pos = str.IndexOf(Char);
            if (Pos < 0) return null;
            return str.Substring(Pos + 1);
        }
        public static string SubstringAfter(this string str, string Key)
        {
            int Pos = str.IndexOf(Key);
            if (Pos < 0) return null;
            return str.Substring(Pos + Key.Length);
        }

        /// <summary>
        /// 与Substring()类似，从左边截取指定长度的字符串，如果 Length 大于字符串本身的长度，则Length将取字符串的完整长度。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Length"></param>
        /// <returns></returns>
        public static string Left(this string str, int Length)
        {
            if (Length <= 0) return string.Empty;
            if (Length >= str.Length) return str;
            return str.Substring(0, Length);
        }
        /// <summary>
        /// 与Substring()类似，从右边截取指定长度的字符串，如果 Length 大于字符串本身的长度，则Length将取字符串的完整长度。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Length"></param>
        /// <returns></returns>
        public static string Right(this string str, int Length)
        {
            if (Length <= 0) return string.Empty;
            if (Length >= str.Length) return str;
            return str.Substring(str.Length - Length);
        }

        /// <summary>
        /// 移除字符串多余的空白字符串。包含首尾所有的空白字符，中间连续多个的空白字符都将变为1个空格。该扩展方法位于 SBS.Common.dll。
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string NormalizeWhiteSpace(this string str)
        {
            System.Text.RegularExpressions.Regex Reg = new Regex(@"\s{2,}");
            return Reg.Replace(str.Trim(), " ");
        }

        /// <summary>
        /// 判断字符串是否JSON数组，支持两种数组：｛"key","value"｝ 与 ["value1","value2"]。注意，两种数组的 key 与 value 都需要双引号包含
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsJsonArray(this string str)
        {
            if (str.StartsWith("{") && str.EndsWith("}"))
            {
                string str2 = str.Replace(" ", "");
                if ((str2.Contains(":") && str2.Length >= 9) || str2.Equals("{}"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (str.StartsWith("[") && str.EndsWith("]"))
            {
                string str2 = str.Replace(" ", "");
                if (str2.Equals("[]") || (str2[1] == '"' && str2[str2.Length - 2] == '"'))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }

    }
    
}
